/** @file

Copyright (c) 2006-2023, ikun BIOS, ikun Technology (Beijing) Co., Ltd.. All
Rights Reserved.

You may not reproduce, distribute, publish, display, perform, modify, adapt,
transmit, broadcast, present, recite, release, license or otherwise exploit
any part of this publication in any form, by any means, without the prior
written permission of ikun Technology (Beijing) Co., Ltd..

Module Name:


Abstract:


Revision History:

**/

#include <Advance.h>
#include <Library/KlSetupVarRWLib.h>
#include "SetupConfig.h"
#include <Guid/MdeModuleHii.h>

#define DEFAULT_MEM_DIMM_NUM    2

extern EFI_SMBIOS_HANDLE               gSmbiosHandle;
extern EFI_SMBIOS_TYPE                 gSmbiosType;

extern EFI_HII_HANDLE           gAdvHiiHandle;
extern EFI_SMBIOS_PROTOCOL      *gSmbiosProtocol;

UINTN                       TotalMemSize = 0;
UINT32                      MemSpeed = 0;
EFI_GUID                    mAdvanceFormGuid = FORMSET_ID_GUID_ADVANCE;

/**

  Update memory information on the main page.

**/
VOID
UpdateMemoryInformation (VOID)
{
  EFI_STATUS                  Status;
  SMBIOS_TABLE_TYPE17         *SmbiosType17Record;
  EFI_SMBIOS_TABLE_HEADER     *SmbiosRecord;
  CHAR8                       *DimmStr;
  CHAR8                       *Manufacture;
  UINT32                      MemSize;
  CHAR16                      DramTypeStr[8];
  CHAR16                      ShowString[128];
  CHAR16                      UDimmString[128];
  //SYSTEM_SETUP_CONFIGURATION          *SetupVar = NULL;
//add-klk-lyang-P000A-start//
  VOID                        *StartOpCodeHandle;
  VOID                        *EndOpCodeHandle;
  EFI_IFR_GUID_LABEL          *StartLabel;
  EFI_IFR_GUID_LABEL          *EndLabel;
  EFI_STRING_ID               PromptToken;
  EFI_STRING_ID               HelpToken;
  EFI_STRING_ID               TextToken;
//add-klk-lyang-P000A-end//
//add-klk-lyang-P000A-start//
  TotalMemSize = 0;
  SmbiosType17Record = NULL;
  SmbiosRecord = NULL;
  MemSize = 0;
  StartOpCodeHandle = NULL;
  EndOpCodeHandle = NULL;
//add-klk-lyang-P000A-end//
  //
  // Update memory information via smbios.
  //
  if (NULL == gSmbiosProtocol) {
    goto EndGetSmbiosInfo;
  }
  //
  // Init OpCode Handle
  //
  StartOpCodeHandle = HiiAllocateOpCodeHandle ();
  ASSERT (StartOpCodeHandle != NULL);

  EndOpCodeHandle = HiiAllocateOpCodeHandle ();
  ASSERT (EndOpCodeHandle != NULL);

  //
  // Create Hii Extend Label OpCode as the start opcode
  //
  StartLabel = (EFI_IFR_GUID_LABEL *) HiiCreateGuidOpCode (StartOpCodeHandle, &gEfiIfrTianoGuid, NULL, sizeof (EFI_IFR_GUID_LABEL));
  StartLabel->ExtendOpCode = EFI_IFR_EXTEND_OP_LABEL;
  StartLabel->Number       = MEM_DEVICE_ENTRY_LABEL;

  //
  // Create Hii Extend Label OpCode as the end opcode
  //
  EndLabel = (EFI_IFR_GUID_LABEL *) HiiCreateGuidOpCode (EndOpCodeHandle, &gEfiIfrTianoGuid, NULL, sizeof (EFI_IFR_GUID_LABEL));
  EndLabel->ExtendOpCode = EFI_IFR_EXTEND_OP_LABEL;
  EndLabel->Number       = MEM_DEVICE_LABEL_END;

  gSmbiosHandle = (gSmbiosType < EFI_SMBIOS_TYPE_MEMORY_DEVICE) ? gSmbiosHandle : SMBIOS_HANDLE_PI_RESERVED;
  gSmbiosType = EFI_SMBIOS_TYPE_MEMORY_DEVICE;

  Status = gSmbiosProtocol->GetNext (gSmbiosProtocol, &gSmbiosHandle, &gSmbiosType, &SmbiosRecord, NULL);
  if (EFI_ERROR(Status)) {
    DEBUG((EFI_D_ERROR, "UpdateMemoryInformation SmbiosProtocol GetNext fail Status=%r\n", Status));
    goto EndGetSmbiosInfo;
  }

  while (!EFI_ERROR(Status)) {
    SmbiosType17Record = (SMBIOS_TABLE_TYPE17 *) SmbiosRecord;
    DimmStr = KlGetSmbiosString (SmbiosRecord, SmbiosType17Record->DeviceLocator);
    ZeroMem(UDimmString, sizeof(UDimmString));
    UnicodeSPrint (UDimmString, sizeof (UDimmString),
                     L"%a",
                     DimmStr);
    PromptToken = HiiSetString (gAdvHiiHandle, 0, UDimmString, NULL);
    HelpToken   = HiiSetString (gAdvHiiHandle, 0, L"", NULL);
    if (SmbiosType17Record->Speed > 0) {
      MemSpeed = SmbiosType17Record->ConfiguredMemoryClockSpeed;      //[yfliu-0005]
      Manufacture = KlGetSmbiosString (SmbiosRecord, SmbiosType17Record->Manufacturer);

      //DEBUG((EFI_D_ERROR, " MemoryType=0x%x\n", SmbiosType17Record->MemoryType));
      ZeroMem(DramTypeStr, sizeof(DramTypeStr));
      if (SMBIOS_MEMORY_DEV_TYPE_DDR4 == SmbiosType17Record->MemoryType) {
        StrCpyS(DramTypeStr, 8*sizeof(UINT16), L"DDR4");
      } else if (SMBIOS_MEMORY_DEV_TYPE_DDR3 == SmbiosType17Record->MemoryType) {
        StrCpyS(DramTypeStr, 8*sizeof(UINT16), L"DDR3");
      }

      //DEBUG((EFI_D_ERROR, " Size=%d\n", SmbiosType17Record->Size));
      //DEBUG((EFI_D_ERROR, " ExtendedSize=%d\n", SmbiosType17Record->ExtendedSize));
      if (SMBIOS_MEMORY_DEV_SIZE_EXTENDED == SmbiosType17Record->Size) {
        MemSize = SmbiosType17Record->ExtendedSize;
      } else {
        MemSize = SmbiosType17Record->Size;
      }

      TotalMemSize += MemSize;

      ZeroMem(ShowString, sizeof(ShowString));
      UnicodeSPrint (ShowString, sizeof (ShowString),
                       L"%a %s %dGB %dMHz",    //[yfliu-0006]
                       Manufacture,
                       DramTypeStr,
                       MemSize/1024,
                       SmbiosType17Record->Speed);   //[yfliu-0006]
      TextToken   = HiiSetString (gAdvHiiHandle, 0, ShowString, NULL);
    } else {
      TextToken   = HiiSetString (gAdvHiiHandle, 0, L"N/A", NULL);
    }
    HiiCreateTextOpCode (
      StartOpCodeHandle,
      PromptToken,
      HelpToken,
      TextToken
    );
    //DEBUG((EFI_D_ERROR, " Speed=%d\n", SmbiosType17Record->Speed));
    Status = gSmbiosProtocol->GetNext (gSmbiosProtocol, &gSmbiosHandle, &gSmbiosType, &SmbiosRecord, NULL);
  }

  //
  // Update MEMORY_SIZE
  //
  InitString (gAdvHiiHandle, STRING_TOKEN (STR_BOARD_MEMORY_SIZE_VALUE), L"%ld GB", TotalMemSize/1024);

  //
  // Update MEMORY_FREQ
  //
  InitString (gAdvHiiHandle, STRING_TOKEN (STR_BOARD_MEMORY_FREQ_VALUE), L"%d MHz", MemSpeed);

EndGetSmbiosInfo:

  HiiUpdateForm (
    gAdvHiiHandle,
    &mAdvanceFormGuid,
    MEMORY_CONFIG_FORM_ID,
    StartOpCodeHandle,
    EndOpCodeHandle
    );

  HiiFreeOpCodeHandle (StartOpCodeHandle);
  HiiFreeOpCodeHandle (EndOpCodeHandle);

  return;
}


